# -*- coding: utf-8 -*-

from ...pao_python.pao.data import process_db, get_cur_time, dataframe_to_list, DataProcess
import pandas as pd
import uuid
import random
import datetime
import json
from enum import Enum
from ...service.mongo_bill_service import MongoBillFilter
from ...service.common import insert_data, find_data, update_data, delete_data, get_condition, get_info, get_current_user_id, get_user_id_or_false
from ...service.buss_pub.bill_manage import (BillManageService, OperationType,
                                             Status, TypeId)
from server.pao_python.pao.service.data.mongo_db import (C, F, MongoFilter,
                                                         MongoService, N,
                                                         as_date)
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
client = AcsClient('LTAI4FwmnrcZqHmNwDEDioc2',
                   'C23sWE0TkgVkzwmQ6KyIELMiu9HemS', 'cn-hangzhou')


class errMsg(Enum):
    telephoneNotExists = '缺少手机号码！'
    actionNotExists = '缺少操作类型！'
    oneMinutesLimit = '60秒内不能重复发送！'
    overTimesLimit = '超过发送次数限制，请稍后再试！'


class SmsManageService(MongoService):

    def __init__(self, db_addr, db_port, db_name, db_user, db_pwd, inital_password, session, request={}):
        self.db_addr = db_addr
        self.db_port = db_port
        self.db_name = db_name
        self.db_user = db_user
        self.db_pwd = db_pwd
        self.inital_password = inital_password
        self.session = session
        self.request = request
        self.bill_manage_service = BillManageService(
            db_addr, db_port, db_name, db_user, db_pwd, inital_password, session)

        # 短信数据库
        self.db_sms = 'PT_Sms'
        # 短信签名
        self.smsSign = '南海健康'
        # 短信模板
        self.templateCode = 'SMS_184206495'
        # 短信有效期时间限制，单位：分钟
        self.minutesLimit = 10
        # 有效期时间限制内的短信次数
        self.timesLimit = 10

        # 测试模式
        self.isTesting = False
        self.testCode = '1234'

    def send_sms(self, condition):
        # 发送短信

        res = 'Failed'

        verifyParam = [
            {'key': 'action', 'errMsg': errMsg.actionNotExists.value},
        ]

        # 获取当前登录的用户id
        user_id = get_user_id_or_false(self.session)

        if 'action' in condition:
            if condition['action'] == 'modifyPassword':
                # 修改用户密码不需要传入手机，而是从数据库拿
                # 获取登录用户的手机号码
                if user_id == False:
                    return '用户未登录！'

                # 找出这个用户
                _filter_user = MongoBillFilter()
                _filter_user.match_bill((C('id') == user_id))\
                    .project({'_id': 0, })
                result_user = self.query(_filter_user, 'PT_User')

                if len(result_user) == 0:
                    return '未知错误，请重新登录！'

                if 'personnel_info' not in result_user[0] or 'telephone' not in result_user[0]['personnel_info']:
                    return '未绑定手机号码！'
                # 手机号码
                telephone = result_user[0]['personnel_info']['telephone']
            elif condition['action'] == 'register':
                # 如果是注册的，就需要判断手机号码是否已经注册
                verifyParam.append(
                    {'key': 'telephone', 'errMsg': errMsg.telephoneNotExists.value})
                # 手机号码
                telephone = condition['telephone']

                _filter_isReg = MongoBillFilter()
                _filter_isReg.match_bill((C('personnel_info.telephone') == telephone))\
                    .project({'_id': 0, })
                result_isReg = self.query(_filter_isReg, 'PT_User')

                if len(result_isReg) > 0:
                    return '当前手机号码已经注册！'
            else:
                # 其他
                verifyParam.append(
                    {'key': 'telephone', 'errMsg': errMsg.telephoneNotExists.value})
                # 手机号码
                telephone = condition['telephone']

        # 验证必须字段
        verifyParamResult = self.verifyParam(verifyParam, condition)

        if verifyParamResult != True:
            return verifyParamResult

        # 验证时间限制
        vartifyTimesResult = self.verfiyLimit(
            telephone, condition['action'], self.request.remote_addr)
        if vartifyTimesResult != True:
            return vartifyTimesResult

        # 存在数据库中的状态
        msg = ''
        # 返回到前端的结果
        returnMsg = ''

        if self.isTesting == True:
            # 测试模式
            code = self.testCode
            # 测试数据
            msg = 'TESTOK'
            returnMsg = 'Success'
        else:
            # 生成验证码
            code = self.create_captcha(6)

            request = CommonRequest()
            request.set_accept_format('json')
            request.set_domain('dysmsapi.aliyuncs.com')
            request.set_method('POST')
            request.set_protocol_type('https')  # https | http
            request.set_version('2017-05-25')
            request.set_action_name('SendSms')

            request.add_query_param('RegionId', "cn-hangzhou")
            request.add_query_param('PhoneNumbers', telephone)
            request.add_query_param('SignName', self.smsSign)
            request.add_query_param('TemplateCode', self.templateCode)
            request.add_query_param(
                'TemplateParam', '{"code": "'+str(code)+'"}')
            response = client.do_action(request)

            response = json.loads(str(response, 'utf-8'))

            # 阿里云接口回复
            msg = response['Message']

            # 阿里云接口状态
            if response['Code'] == 'OK':
                returnMsg = 'Success'
            else:
                returnMsg = msg

        # 存数据库
        def process_func(db):
            nonlocal res
            now_date = get_cur_time()
            data_info = {
                # 手机号码
                'telephone': telephone,
                # 验证码
                'code': code,
                # 操作类型
                'action': condition['action'],
                # 请求的IP地址
                'ip': self.request.remote_addr,
                # 主键ID
                'id': str(uuid.uuid1()),
                # 保存结果
                'msg': msg,
                # 时间数据
                'create_date': now_date,
                'modify_date': now_date,
            }
            # 可能存在的用户ID
            if user_id != False:
                data_info['user_id'] = user_id
            insert_data(db, self.db_sms, data_info)
        process_db(self.db_addr, self.db_port, self.db_name,
                   process_func, self.db_user, self.db_pwd)
        return returnMsg

    # 验证验证码是否合法
    def verifyCode(self, action, telephone, code):
        verify_date = self.getVerifyDate()
        _filter = MongoBillFilter()
        _filter.match(
            (C('telephone') == telephone) & (C('action') == action) & (C('code') == code) & (C('create_date') > verify_date)).project({'_id': 0})
        length = len(self.query(
            _filter, self.db_sms))
        if length == 0:
            return False
        return True

    # 根据时间有效期获取时间对象
    def getVerifyDate(self):
        return datetime.datetime.now()-datetime.timedelta(minutes=self.minutesLimit)

    # 验证必须字段
    def verifyParam(self, cfg, data):
        for item in cfg:
            keyTmp = item.get('key')
            if keyTmp not in data or data[keyTmp] == '' or data[keyTmp] == None:
                return item.get('errMsg')
        return True

    # 检测是否超过获取机制
    def verfiyLimit(self, telephone, action, ip):
        verify_date = self.getVerifyDate()

        # 同一个IP地址同一个手机号码同换一个操作一分钟内不允许重发
        oneMinutes = datetime.datetime.now()-datetime.timedelta(minutes=1)
        _filter = MongoBillFilter()
        _filter.match(
            (C('telephone') == telephone) & (C('ip') == ip) & (C('action') == action) & (C('create_date') > oneMinutes)).project({'_id': 0})
        lengthOneMinutes = len(self.query(
            _filter, self.db_sms))

        if lengthOneMinutes > 0:
            return errMsg.oneMinutesLimit.value

        # 同一个IP同一个手机号码单位时间内的次数限制
        limitMinutes = datetime.datetime.now()-datetime.timedelta(minutes=self.minutesLimit)
        _filter = MongoBillFilter()
        _filter.match(
            (C('telephone') == telephone) & (C('ip') == ip) & (C('create_date') > limitMinutes)).project({'_id': 0})
        lengthlimitMinutes = len(self.query(
            _filter, self.db_sms))

        if lengthlimitMinutes >= self.timesLimit:
            return errMsg.overTimesLimit.value
        return True

    # 生成验证码
    def create_captcha(self, length):
        captcha = ''
        for i in range(length):
            rad = str(random.randint(0, 9))
            # 第一位是'0'的时候发出去有可能会丢失第一位，所以不能尽量不要是'0'
            if captcha == '' and rad == '0':
                captcha += '6'
            else:
                captcha += rad
        return captcha
